package designpatterns.creation;

import java.io.Serializable;

/**
 * 原型模式
 * 用一个已经创建的实例作为原型，通过复制该原型对象来创建一个和原型相同或相似的新对象
 * 浅拷贝：只复制对象的其中的值类型的成员变量，而引用类型的成员变量没有复制
 * 深拷贝：除了对象本身被复制外，对象所包含的所有成员变量都会被复制，包括引用类型的成员对象
 *
 * @author jack.wu
 * @since 2019/9/18
 */
public class PrototypeTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        SunWuKong sunWuKong = new SunWuKong();
        sunWuKong.setId(1);
        sunWuKong.setName("大猴");
        SunWuKong clone = sunWuKong.clone();
        clone.setName("三猴");
        System.out.println(sunWuKong.getName());
        System.out.println(clone.getName());
        System.out.println("------------------");
        Animal animal = new Animal("棕色", "猴子", sunWuKong);
        Animal clone1 = animal.clone();
        clone1.getSunWuKong().setName("二猴");
        System.out.println(animal.getSunWuKong().getName());
        System.out.println(clone1.getSunWuKong().getName());

    }

}

/**
 * 优点：当创建新的对象实例较为复杂时，使用原型模式可以简化的对象的创建过程，
 * 通过复制一个已有实例可以提高新实例的创建效率。
 * 缺点：原型模式的最主要缺点就是每一个类必须配备一个克隆方法。
 * 而且这个克隆方法需要对类的功能进行通盘考虑，这对全新的类来说不是很难，
 * 但对已有的类进行改造时，不一定是件容易的事。
 */
class SunWuKong implements Cloneable, Serializable {
    private Integer id;
    private String name;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    protected SunWuKong clone() throws CloneNotSupportedException {
        return (SunWuKong) super.clone();
    }

}

class Animal implements Cloneable, Serializable {

    private String color;
    private String sex;
    private SunWuKong sunWuKong;

    public Animal(String color, String sex, SunWuKong sunWuKong) {
        this.color = color;
        this.sex = sex;
        this.sunWuKong = sunWuKong;
    }

    public Animal() {
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public SunWuKong getSunWuKong() {
        return sunWuKong;
    }

    public void setSunWuKong(SunWuKong sunWuKong) {
        this.sunWuKong = sunWuKong;
    }

    @Override
    protected Animal clone() throws CloneNotSupportedException {
        Animal o = (Animal) super.clone();
        o.sunWuKong = sunWuKong.clone();
        return o;
    }

}
